package com.cyou.nad.datastore;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

import com.cyou.nad.datastore.exception.ColumnTypeNotMatchException;
import com.cyou.nad.datastore.exception.DataListFormarValueException;
import com.cyou.nad.datastore.exception.InvalidRowColException;

/**
 * 抽象类，提供了DataList 的基本实现
 * @author lzm 
 */
public class AbstractDataList implements DataList {

	private static final long serialVersionUID = -3130993380007969886L;
	protected Log log = LogFactory.getLog(getClass());
	protected List<DSRow> rowList = new ArrayList<DSRow>();
	protected List<DBHeader> headerList = new ArrayList<DBHeader>();

	private Map<String,Integer>colMap=null;
	
	public int colCount() {
		return headerList.size();

	}

	public DataList clone() {
		DataList cloneobj = null;
		ObjectInputStream ois = null;
		 ObjectOutputStream  oos = null;
		try {
			//把对象对到内存中去   
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			oos = new ObjectOutputStream( out);
			oos.writeObject(this);
			//把对象从内存中读出来             
			ois = new ObjectInputStream( new ByteArrayInputStream(out.toByteArray()));
			cloneobj = (DataList) ois.readObject();
			return cloneobj;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("克隆对象出错",e);
		}finally{
			try {
				oos.close();
			} catch (Exception e) {
			}
			try {
				ois.close();
			} catch (Exception e) {
			}
		}
	}
	public void changeColValueByCondition(String[] conditionCol,String[] destCol,ChangeColValueByConditionCallBack condition){
		if(colCount()==0)
			return;
		Assert.isTrue(conditionCol.length==destCol.length,"conditionCol和destCol必须一一对应");
		int[] c1= new int[conditionCol.length];
		int[] d1= new int[conditionCol.length];
		for (int i = 0; i < conditionCol.length; i++) {
			c1[i]=colName2ColNo(conditionCol[i]);
			d1[i]=colName2ColNo(destCol[i]);
		}
		changeColValueByCondition(c1, d1, condition);
	}
	
	public void changeColValueByCondition(String conditionCol,String destCol,ChangeColValueByConditionCallBack condition){
		this.changeColValueByCondition(new String[]{conditionCol}, new String[]{destCol}, condition);
	}
	
	public void changeColValueByCondition(int conditionCol,int destCol,ChangeColValueByConditionCallBack condition){
		this.changeColValueByCondition(new int[]{conditionCol}, new int[]{destCol}, condition);
	}
	public void changeColValueByCondition(int[] conditionCol,int[] destCol,ChangeColValueByConditionCallBack condition){
		Assert.isTrue(conditionCol.length==destCol.length,"conditionCol和destCol必须一一对应");
		int colCount = this.colCount();
		for (int i = 0; i < destCol.length; i++) {
			if(destCol[i]>colCount){
				throw new RuntimeException("destCol越界，col最大值="+colCount +"\tdestcol="+destCol[i]);
			}
			if(conditionCol[i]>colCount){
				throw new RuntimeException("conditionCol越界，col最大值="+colCount +"\tconditionCol="+conditionCol[i]);
			}
		}
		if(colCount==0||this.rowCount()==0)
			return ;
		for (int row = 0; row < this.rowCount(); row++) {
			for (int i = 0; i < conditionCol.length; i++) {
					condition.changeValue(row, conditionCol[i], destCol[i],this);
			}
		}
	}
	
	public void delCol(int col) throws InvalidRowColException {
		if (col < 0 || col > headerList.size() - 1)
			throw new InvalidRowColException(0, col);
		headerList.remove(col);
		for (DSRow row : rowList) {
			row.deleteColumn(col);
		}
	}

	public void delRow(int row) throws InvalidRowColException {
		if (row < 0 || row > rowList.size() - 1)
			throw new InvalidRowColException(row, 0);
		rowList.remove(row);
	}

	public ColType getColType(int col) throws InvalidRowColException {
		return getHeader(col).getColType();
	}

	public ColType getColType(String colName) throws InvalidRowColException {
		return getHeader(colName).getColType();
	}

	public Timestamp getTimestamp(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (getColType(col).equals(ColType.TIMESTAMP))
			throw new ColumnTypeNotMatchException(ColType.DATE, getColType(col), col);
		return (Timestamp) getObject(row, col);
	}

	public Timestamp getTimestamp(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (getColType(col).equals(ColType.TIMESTAMP))
			throw new ColumnTypeNotMatchException(ColType.DATE, getColType(col), col);
		return (Timestamp) getObject(row, col);
	}

	public Date getDate(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).equals(ColType.DATE) && !getColType(col).equals(ColType.TIMESTAMP))
			throw new ColumnTypeNotMatchException(ColType.DATE, getColType(col), col);
		return (Date) getObject(row, col);
	}

	public Date getDate(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).equals(ColType.DATE) && !getColType(col).equals(ColType.TIMESTAMP))
			throw new ColumnTypeNotMatchException(ColType.DATE, getColType(col), col);
		return (Date) getObject(row, col);
	}

	public Double getDouble(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.DOUBLE, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).doubleValue();
	}

	public Double getDouble(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.DOUBLE, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).doubleValue();
	}

	public Float getFloat(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.FLOAT, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).floatValue();
	}

	public Float getFloat(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.FLOAT, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).floatValue();
	}
	public Long getLong(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.LONG, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).longValue();
	}

	public Long getLong(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.LONG, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).longValue();
	}

	public Integer getInt(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.INTEGER, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).intValue();
	}

	public Integer getInt(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).isNumberType())
			throw new ColumnTypeNotMatchException(ColType.INTEGER, getColType(col), col);
		Object object = getObject(row, col);
		return object==null?null:((Number) object).intValue();
	}
	
	@Override
	public BigDecimal getBigDecimal(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if(getColType(col).equals(ColType.INTEGER)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).intValue());
		}
		if(getColType(col).equals(ColType.LONG)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).longValue());
		}
		if(getColType(col).equals(ColType.DOUBLE)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).doubleValue());
		}
		if(getColType(col).equals(ColType.FLOAT)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).floatValue());
		}
		throw new ColumnTypeNotMatchException("第"+col+"列类型是"+getColType(col)+"，不能转换成BigDecimal");
	}

	@Override
	public BigDecimal getBigDecimal(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if(getColType(col).equals(ColType.INTEGER)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).intValue());
		}
		if(getColType(col).equals(ColType.LONG)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).longValue());
		}
		if(getColType(col).equals(ColType.DOUBLE)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).doubleValue());
		}
		if(getColType(col).equals(ColType.FLOAT)){
			Object object = getObject(row, col);
			return object==null?null:new BigDecimal(((Number) object).floatValue());
		}
		throw new ColumnTypeNotMatchException("第"+col+"列类型是"+getColType(col)+"，不能转换成BigDecimal");
	}

	protected DBHeader getHeader(int colNo) throws InvalidRowColException {
		if (!isValidCol(colNo))
			throw new InvalidRowColException(0, colNo);
		return headerList.get(colNo);
	}

	private DBHeader getHeader(String colName) throws InvalidRowColException {
		int col=colName2ColNo(colName);
		return getHeader(col);
	}

	public List<DBHeader> getHeaders() {
		return headerList;
	}

	public Object getObject(int row, int col) throws InvalidRowColException {
		if (!isValidRowCol(row, col))
			throw new InvalidRowColException(row, col);
		return rowList.get(row).getCell(col);
	}

	public Object getObject(int row, String colName) throws InvalidRowColException {
		int col = colName2ColNo(colName);
		return getObject(row, col);
	}
	
	public int colName2ColNo(String colName){
		if(colCount()==0)
			return 0;
		if(colMap==null){
			initColMap();
		}
		Integer i =  colMap.get(colName.toUpperCase());
		if(i==null){
			throw new RuntimeException("不正确的行名称："+colName);
		}
		return i.intValue();
	}

	private void initColMap() {
		colMap= new HashMap<String, Integer>();
		int col=0;
		for (DBHeader header : headerList) {
			colMap.put(header.getColDBName().toUpperCase(), col);
			col++;
		}
	}

	public String getString(int row, int col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).equals(ColType.STRING))
			throw new ColumnTypeNotMatchException(ColType.STRING, getColType(col), col);
		return (String) getObject(row, col);
	}

	public String getString(int row, String col) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (!getColType(col).equals(ColType.STRING))
			throw new ColumnTypeNotMatchException(ColType.STRING, getColType(col), col);
		return (String) getObject(row, col);
	}

	public void insertRow(int row) {
		if (row < -1 || row >= rowCount())
			throw new InvalidRowColException(row, "");
		DSRow row1 = new DSRow(colCount());
		if (row == -1) {
			rowList.add(row1);
			return;
		}

		rowList.add(row, row1);
	}

	protected boolean isValidCol(int col) {
		if (col < 0)
			return false;
		if (col > headerList.size() - 1)
			return false;
		return true;
	}

	protected boolean isValidRowCol(int row, int col) {
		if (row < 0 || col < 0)
			return false;
		if (rowList.isEmpty())
			return true;
		if (headerList.isEmpty())
			return true;
		if (row > rowList.size() - 1 || col > headerList.size() - 1)
			return false;
		return true;
	}

	protected void preSetCheck(int row, int col, Object obj) throws InvalidRowColException, ColumnTypeNotMatchException {
		if (obj == null)
			return;
		if (!isValidRowCol(row, col))
			throw new InvalidRowColException(row, col);
		ColType colType = getColType(col);
		if (colType == null)
			throw new ColumnTypeNotMatchException("必须指定列数据类型");
//		if (!colType.match(obj))
//			throw new ColumnTypeNotMatchException(colType, ColType.parse(obj));
	}

	public void printDebug(int rowNum) {
		//		System.out.println("row num:" + rowCount());
		//		System.out.println("col num:" + colCount());
		int j = rowNum;
		if (rowNum < 0 || rowNum > rowCount())
			j = rowCount();
		else
			j = rowNum;
		for (int i = 0; i < j; i++) {
			for (int k = 0; k < colCount(); k++) {
				System.out.print(getStringWithFormart(i, k, FormatType.getDefaultParam()) + "\t");
			}
			System.out.println();
		}
		System.out.println("row num:" + rowCount());
		System.out.println("col num:" + colCount());
	}

	public boolean reset() {
		throw new UnsupportedOperationException();
	}

	public int rowCount() {
		return rowList.size();
	}

	@SuppressWarnings("rawtypes")
	protected void addCell(int row, int col, Comparable value) throws InvalidRowColException,
			ColumnTypeNotMatchException {
		preSetCheck(row, col, value);
		rowList.get(row).addCell(col, value);
	}
	@SuppressWarnings("rawtypes")
	public void setCell(int row, int col, Comparable value) throws InvalidRowColException, ColumnTypeNotMatchException {
		preSetCheck(row, col, value);
		rowList.get(row).setCell(col, value);
	}

	@SuppressWarnings("rawtypes")
	public void setCell(int row, String col, Comparable value) throws InvalidRowColException, ColumnTypeNotMatchException {
		int colNum = colName2ColNo(col);
		preSetCheck(row, colNum, value);
		rowList.get(row).setCell(colNum, value);
	}
	
	public void insertCol(int colIndex, ColType colType, String colName) {
		if (colIndex < -1 || colIndex > colCount())
			throw new IllegalArgumentException("插入列的时候colIndex取值范围 【-1,colCount】");
		DBHeader header = new DBHeader();
		header.setColDBName(colName);
		header.setColType(colType);
		if (colIndex == -1) {
			headerList.add(header);
		} else {
			headerList.add(colIndex, header);
		}
		for (DSRow row : rowList) {
			row.insertColumn(colIndex, null);
		}
	}


	public String getStringWithFormart(int row, int col, Map<FormatType, String> formarParam)
			throws InvalidRowColException, DataListFormarValueException {
		Object obj = getObject(row, col);
		return formartValue(formarParam, obj, col);
	}

	public String getStringWithFormart(int row, String col, Map<FormatType, String> formarParam)
			throws InvalidRowColException, DataListFormarValueException {
		Object obj = getObject(row, col);
		return formartValue(formarParam, obj, col);
	}

	private String formartValue(Map<FormatType, String> formarParam, Object obj, Object col) {
		if (obj == null)
			return "";
		if (formarParam == null || formarParam.isEmpty())
			return obj.toString();
		try {
			if (obj instanceof Date) {
				if (formarParam.get(FormatType.DATE) == null)
					throw new DataListFormarValueException("行：" + col + "\t 类型是日期类型，但是没有指定得日期类型的格式化方式");
				return DateFormatUtils.format((Date) obj, formarParam.get(FormatType.DATE));
			}
			if (obj instanceof Number) {
				if (formarParam.get(FormatType.NUMBER) == null)
					throw new DataListFormarValueException("行：" + col + "\t 类型是数字类型，但是没有指定得数字类型的格式化方式");
				DecimalFormat decimalFormat = new DecimalFormat(formarParam.get(FormatType.NUMBER));
				return decimalFormat.format(obj);
			}
		} catch (RuntimeException e) {
			throw new DataListFormarValueException("行：" + col + "\t 格式化数据出现错误！");
		}

		return obj.toString();
	}
	


	public void sort(final int col, final SortType param) {
		if (col < 0 || col >= colCount())
			throw new InvalidRowColException(0, col);
		Collections.sort(rowList, new Comparator<DSRow>() {

			@SuppressWarnings("unchecked")
			public int compare(DSRow o1, DSRow o2) {
				if (param.equals(SortType.asc))
					return o1.getCell(col).compareTo(o2.getCell(col));
				else
					return -1 * o1.getCell(col).compareTo(o2.getCell(col));
			}
		});
	}


	@SuppressWarnings("rawtypes")
	@Override
	public List getRow(int i) {
		if(i<0||i>=rowList.size())
			throw new InvalidRowColException(i,0);
		return rowList.get(i).dataList;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public DataList filter(int col, Comparable value) {
		AbstractDataList ret = (AbstractDataList) this.clone();
		List<DSRow> rowList = new ArrayList<DSRow>();;
		for (DSRow dsRow : ret.rowList) {
			Comparable c=dsRow.getCell(col);
			if(c.compareTo(value)==0){
				rowList.add(dsRow);
			}
		}
		ret.rowList=rowList;
		return ret;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public DataList filter(String colName, Comparable value) {
		AbstractDataList ret = (AbstractDataList) this.clone();
		List<DSRow> rowList = new ArrayList<DSRow>();
		if(colMap==null){
			initColMap();
		}
		Integer col= colMap.get(colName.toUpperCase());
		if(col==null){
			throw new InvalidRowColException(-1, colName);
		}
		for (DSRow dsRow : ret.rowList) {
			Comparable c=dsRow.getCell(col);
			if(c.compareTo(value)==0){
				rowList.add(dsRow);
			}
		}
		ret.rowList=rowList;
		return ret;
	}
	@SuppressWarnings("serial")
	public static void main(String[] args) {

		AbstractDataList dataList = new AbstractDataList() {

		};

		String value = dataList.formartValue(DataList.FormatType.getDefaultParam(), new Date(), 1);
		System.out.println(value);

		value = dataList.formartValue(DataList.FormatType.getDefaultParam(), 1, 1);
		System.out.println(value);

		value = dataList.formartValue(DataList.FormatType.getDefaultParam(), 111111, 1);
		System.out.println(value);

		value = dataList.formartValue(DataList.FormatType.getDefaultParam(), 1111111.11111, 1);
		System.out.println(value);
	}

	





}
